﻿/*
 * String.h
 */

#ifndef __GDK_STRING_H__
#define __GDK_STRING_H__


#include <gdk/core/Types.h>
#include <gdk/core/atomics.h>
#include <gdk/core/Memory.h>
#include <gdk/core/Exception.h>
#include <gdk/core/CodePage.h>
#include <gdk/core/stdlib.h>
#include <gdk/core/Log.h>
#include <gdk/core/Varint.h>


namespace gdk
{

#if defined(_WIN32)
#	pragma warning(push)
#	pragma warning(disable:4127)
#endif


//---------------------------------------------------
__INLINE__ int charUppercase(int ch)
{
	if ('a' <= ch && ch <= 'z')
	{
		ch += ('A' - 'a');
	}
	return ch;
}
__INLINE__ int charLowercase(int ch)
{
	if ('A' <= ch && ch <= 'Z')
	{
		ch += ('a' - 'A');
	}
	return ch;
}
//---------------------------------------------------
__INLINE__ ssize_t stringBufferLength(const ansi_t *psz)
{
	return (ssize_t)::strlen((const char*)psz) + 1;
}

__INLINE__ ssize_t stringBufferLength(const utf8_t *psz)
{
	return (ssize_t)::strlen((const char*)psz) + 1;
}

__INLINE__ ssize_t stringBufferLength(const wchar_t *psz)
{
	return ((ssize_t)::wcslen(psz) + 1) * sizeof(wchar_t);
}
//---------------------------------------------------
__INLINE__ ssize_t stringCharLength(const ansi_t *psz)
{
	return ((*psz) & 0x80) ? 2 : 1;
}

GDK_CORE_EXPORT ssize_t stringCharLength(const utf8_t *psz);

__INLINE__ ssize_t stringCharLength(const wchar_t *psz)
{
	(void)&psz;

	return 1;
}
//-------------------------------------------------
GDK_CORE_EXPORT ansi_t* stringChar(const ansi_t *psz, int &ch);
GDK_CORE_EXPORT utf8_t* stringChar(const utf8_t *psz, int &ch);
__INLINE__ wchar_t* stringChar(const wchar_t *psz, int &ch)
{
	ch = *psz ++;
	return (wchar_t*)psz;
}
//-------------------------------------------------
GDK_CORE_EXPORT ssize_t stringLength(const ansi_t *s);
GDK_CORE_EXPORT ssize_t stringLength(const utf8_t *s);
__INLINE__ ssize_t stringLength(const wchar_t *s)
{
	return (ssize_t)::wcslen(s);
}
//-------------------------------------------------
template<typename TyChar>
__INLINE__ TyChar* stringSkipChar(TyChar *s, ssize_t i)
{
	GDK_ASSERT(i >= 0 && i <= stringLength(s));

	while (i-- > 0)
	{
		s += stringCharLength(s);
	}

	return s;
}
__INLINE__ wchar_t* stringSkipChar(wchar_t* s, ssize_t i)
{
	GDK_ASSERT(i >= 0 && i <= stringLength(s));

	return s + i;
}
__INLINE__ wchar_t const* stringSkipChar(wchar_t const *s, ssize_t i)
{
	GDK_ASSERT(i >= 0 && i <= stringLength(s));

	return s + i;
}
//-------------------------------------------------
template<typename TyChar>
__INLINE__ ssize_t charLength(int ch)
{
	GDK_ASSERT(false); return 0;
}
template<>
GDK_CORE_EXPORT ssize_t charLength<ansi_t>(int ch);
template<>
__INLINE__ ssize_t charLength<utf8_t>(int ch)
{
	/*
	0000007F: 0xxxxxxx
	000007FF: 110xxxxx 10xxxxxx
	0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
	*/
	if ((ch & 0xff80) == 0) return 1;
	if ((ch & 0xf800) == 0) return 2;
	return 3;
}
template<>
__INLINE__ ssize_t charLength<wchar_t>(int ch)
{
	(void)&ch;

	return 1;
}
//-------------------------------------------------
GDK_CORE_EXPORT ssize_t charToString(ansi_t *psz, int ch);
GDK_CORE_EXPORT ssize_t charToString(utf8_t *psz, int ch);
__INLINE__ ssize_t charToString(wchar_t *psz, int ch)
{
	int n = 0;

	ch &= 0x0000ffff;
	if (ch)
	{
		psz[n ++] = (wchar_t)ch;
	}
	psz[n] = 0;

	return n;
}
//---------------------------------------------------
template<typename Ty1, typename Ty2>
Ty1* stringFindString(Ty1 *string, Ty2 *sub)
{
	Ty1 *cp, *s1;
	Ty2 *s2;
	ssize_t count;

	if (*sub == '\0')
		return string;

	cp = string;
	count = stringLength(string) - stringLength(sub);

	while (*cp && count-- >= 0)
	{
		s1 = cp;
		s2 = sub;

		for (;;) {
			int c1, c2;

			s2 = stringChar(s2, c2);
			if (c2 == 0) return cp;

			s1 = stringChar(s1, c1);
			if (c1 != c2) break;
		}

		int c;
		cp = stringChar(cp, c);
	}

	return(NULL);
}

__INLINE__ char* stringFindString(char *string, const char *sub)
{
	return ::strstr(string, sub);
}
__INLINE__ const char * stringFindString(const char *string, const char *sub)
{
	return ::strstr(string, sub);
}

__INLINE__ wchar_t* stringFindString(wchar_t *string, const wchar_t *sub)
{
	return ::wcsstr(string, sub);
}
__INLINE__ const wchar_t * stringFindString(const wchar_t *string, const wchar_t *sub)
{
	return ::wcsstr(string, sub);
}
//----------------------------------------------------
template<typename Ty>
__INLINE__ Ty* stringFindChar(Ty *string, int ch)
{
	for (;;) {

		int c;

		Ty *str = stringChar(string, c);

		if (c == ch)
			return string;

		if (c == 0)
			break;

		string = str;
	}

	return NULL;
}

__INLINE__ wchar_t* stringFindChar(wchar_t *string, int ch)
{
	return ::wcschr(string, (wchar_t)ch);
}
__INLINE__ const wchar_t* stringFindChar(const wchar_t *string, int ch)
{
	return ::wcschr(string, (wchar_t)ch);
}
//-----------------------------------------------
template<typename Ty1, typename Ty2>
__INLINE__ int stringCompare(const Ty1 *s1, const Ty2 *s2)
{
	for (;;) {

		int c1, c2;

		s1 = stringChar(s1, c1);
		s2 = stringChar(s2, c2);

		if (c1 != c2)
			return (c1 > c2) ? 1 : -1;

		if (c1 == 0)
			return 0;
	}
}

__INLINE__ static int stringCompare(const char *s1, const char *s2)
{
	return ::strcmp(s1, s2);
}

__INLINE__ int stringCompare(const wchar_t *s1, const wchar_t *s2)
{
	return ::wcscmp(s1, s2);
}
//-----------------------------------------------
template<typename Ty1, typename Ty2>
__INLINE__ int stringCompareNoCase(const Ty1 *s1, const Ty2 *s2)
{
	for (;;) {

		int c1, c2;

		s1 = stringChar(s1, c1);
		s2 = stringChar(s2, c2);

		if ('A' <= c1 && c1 <= 'Z') {
			c1 += ('a' - 'A');
		}
		if ('A' <= c2 && c2 <= 'Z') {
			c2 += ('a' - 'A');
		}

		if (c1 != c2)
			return (c1 > c2) ? 1 : -1;

		if (c1 == 0)
			return 0;
	}
}

__INLINE__ static int stringCompareNoCase(const char *s1, const char *s2)
{
#ifdef _WIN32
	return ::stricmp(s1, s2);
#else
	return ::strcasecmp(s1, s2);
#endif
}

__INLINE__ static int stringCompareNoCase(const wchar_t *s1, const wchar_t *s2)
{
#ifdef _WIN32
	return ::wcsicmp(s1, s2);
#else
	return ::wcscasecmp(s1, s2);
#endif
}
//-----------------------------------------------
/*
__INLINE__ char* stringUppercase(char *psz)
{
	return (char *)::_mbsupr((unsigned char *)psz);
}

__INLINE__ unsigned char* stringUppercase(unsigned char *psz)
{
	return (unsigned char *)::strupr((char*)psz);
}

__INLINE__ wchar_t* stringUppercase(wchar_t *psz)
{
	return ::wcsupr(psz);
}
*/
__INLINE__ ansi_t* stringUppercase(ansi_t *psz)
{//ANSI
	ansi_t *p = psz;
	while (*p)
	{
		ssize_t ret = stringCharLength(p);
		if (ret == 1)
		{
			if ('a' <= *p && *p <= 'z')
			{
				*p += (ansi_t)('A' - 'a');
			}
		}
		p += ret;
	}
	return psz;
}
template<typename TyChar>
__INLINE__ TyChar* stringUppercase(TyChar *psz)
{//_UNICODE AND UTF8
	for (TyChar *p = psz; *p; ++p)
	{
		if ('a' <= *p && *p <= 'z')
		{
			*p += (TyChar)('A' - 'a');
		}
	}
	return psz;
}
//-----------------------------------------------
/*
__INLINE__ char* stringLowercase(char *psz)
{
	return (char*)::_mbslwr((unsigned char*)psz);
}

__INLINE__ unsigned char* stringLowercase(unsigned char *psz)
{
	return (unsigned char *)::strlwr((char*)psz);
}

__INLINE__ wchar_t* stringLowercase(wchar_t *psz)
{
	return ::wcslwr(psz);
}
*/
__INLINE__ ansi_t* stringLowercase(ansi_t *psz)
{//ANSI
	ansi_t *p = psz;
	while (*p)
	{
		ssize_t ret = stringCharLength(p);
		if (ret == 1)
		{
			if ('A' <= *p && *p <= 'Z')
			{
				*p += (ansi_t)('a' - 'A');
			}
		}
		p += ret;
	}
	return psz;
}
template<typename TyChar>
__INLINE__ TyChar* stringLowercase(TyChar *psz)
{//_UNICODE AND UTF8
	for (TyChar *p = psz; *p; ++p)
	{
		if ('A' <= *p && *p <= 'Z')
		{
			*p += (TyChar)('a' - 'A');
		}
	}
	return psz;
}
//-----------------------------------------------
/*
__INLINE__ bool isSpace(int ch)
{
	return ::isspace(ch) != 0;
}

__INLINE__ bool isSpace(unsigned int ch)
{
	return ::isspace((int)ch)!=0;
}

__INLINE__ bool isSpace(wchar_t ch)
{
	return ::isspace((int)ch)!=0;
}
*/
__INLINE__ bool isSpace(int ch)
{//0x9,0xa,0xb,0xc,0xd,0x20,
	return((unsigned int)ch < 0x80 && ::isspace(ch) != 0);
}
//-----------------------------------------------
#ifdef _WIN32

__INLINE__ ssize_t ansiToWide(wchar_t *pszDest, ssize_t destLength, const ansi_t *pszSrc)
{
	return ::MultiByteToWideChar(getCodePage(), 0, (char*)pszSrc, -1, pszDest, (destLength > INT32_MAX ? -1 : (int)destLength));
}
__INLINE__ ssize_t wideToAnsi(ansi_t *pszDest, ssize_t destLength, const wchar_t *pszSrc)
{
	return ::WideCharToMultiByte(getCodePage(), 0, pszSrc, -1, (char*)pszDest, (destLength > INT32_MAX ? -1 : (int)destLength), NULL, NULL);
}
__INLINE__ ssize_t wideToUtf8(utf8_t *pszDest, ssize_t destLength, const wchar_t *pszSrc)
{
	return ::WideCharToMultiByte(CP_UTF8, 0, pszSrc, -1, (char*)pszDest, (destLength > INT32_MAX ? -1 : (int)destLength), NULL, NULL);
}
__INLINE__ ssize_t utf8ToWide(wchar_t *pszDest, ssize_t destLength, const utf8_t *pszSrc)
{
	return ::MultiByteToWideChar(CP_UTF8, 0, (const char*)pszSrc, -1, pszDest, (destLength > INT32_MAX ? -1 : (int)destLength));
}

#else

__INLINE__ ssize_t ansiToWide(wchar_t *pszDest, ssize_t destLength, const ansi_t *pszSrc)
{
	return ::mbsrtowcs(pszDest, (const char**)&pszSrc, destLength, NULL) + 1;
}
__INLINE__ ssize_t wideToAnsi(ansi_t *pszDest, ssize_t destLength, const wchar_t *pszSrc)
{
	return ::wcsrtombs((char*)pszDest, &pszSrc, destLength, NULL) + 1;
}
GDK_CORE_EXPORT ssize_t wideToUtf8(utf8_t *pszDest, ssize_t destLength, const wchar_t *pszSrc);
GDK_CORE_EXPORT ssize_t utf8ToWide(wchar_t *pszDest, ssize_t destLength, const utf8_t *pszSrc);

#endif

//-------------------------------------------------------------
#ifdef _WIN32

__INLINE__ ssize_t getFormatLength(const char *pszFormat, va_list args)
{
	return ::_vscprintf((const char *)pszFormat, args);
}
__INLINE__ ssize_t getFormatLength(const unsigned char *pszFormat, va_list args)
{
	return ::_vscprintf((const char *)pszFormat, args);
}
__INLINE__ ssize_t getFormatLength(const wchar_t *pszFormat, va_list args)
{
	return ::_vscwprintf((const wchar_t *)pszFormat, args);
}

__INLINE__ ssize_t vsprintf(char *pszBuffer, const char *pszFormat, va_list args)
{
	return ::vsprintf(pszBuffer, pszFormat, args);
}
__INLINE__ ssize_t vsprintf(unsigned char *pszBuffer, const unsigned char *pszFormat, va_list args)
{
	return ::vsprintf((char *)pszBuffer, (const char *)pszFormat, args);
}
__INLINE__ ssize_t vsprintf(wchar_t *pszBuffer, const wchar_t *pszFormat, va_list args)
{
	return ::vswprintf(pszBuffer, pszFormat, args);
}

#else

GDK_CORE_EXPORT ssize_t getFormatLength(const char *pszFormat, va_list args);
__INLINE__ ssize_t getFormatLength(const unsigned char *pszFormat, va_list args)
{
	return getFormatLength((const char *)pszFormat, args);
}
GDK_CORE_EXPORT ssize_t getFormatLength(const wchar_t *pszFormat, va_list args);

__INLINE__ ssize_t vsprintf(char *pszBuffer, const char *pszFormat, va_list args)
{
	return ::vsprintf(pszBuffer, pszFormat, args);
}
__INLINE__ ssize_t vsprintf(unsigned char *pszBuffer, const unsigned char *pszFormat, va_list args)
{
	return ::vsprintf((char *)pszBuffer,(const char *)pszFormat, args);
}
GDK_CORE_EXPORT ssize_t vsprintf(wchar_t *pszBuffer, const wchar_t *pszFormat, va_list args);


#endif


////////////////////////////////////////////
template<typename Tychar>
class String_T
{
public:
	typedef Tychar TyChar;

private:
	struct StringData
	{
	public:
		ssize_t			_bufferLength;
		ssize_t	mutable	_stringLength;
		int32_t			_refs;

	public:
		__INLINE__ TyChar* data(void)
		{
			return (TyChar*)(this + 1);
		}

		__INLINE__ TyChar const* data(void) const
		{
			return (TyChar const*)(this + 1);
		}

		__INLINE__ StringData* addRefs(void)
		{
			atomic_increment(&_refs);

			return this;
		}

		__INLINE__ void release(void)
		{
			if(atomic_decrement(&_refs) == 0)
			{
				delete [] (char*)this;
			}
		}

		__INLINE__ int32_t getRefs(void) const
		{
			return _refs;
		}

		__INLINE__ bool isShared(void) const
		{
			return getRefs() != 1;
		}

	private:
		ssize_t getStringLength_(void) const
		{
			GDK_ASSERT(sizeof(TyChar) != sizeof(wchar_t));

			if (_stringLength < 0)
			{
				_stringLength = stringLength(data());
			}
			return _stringLength;
		}
	public:
		__INLINE__ ssize_t getStringLength(void) const
		{
			if (sizeof(TyChar) != sizeof(wchar_t))
			{
				return getStringLength_();
			}

			GDK_ASSERT(_stringLength == (ssize_t)(getBufferLength() / sizeof(wchar_t) - 1));

			return _stringLength;
		}

		__INLINE__ void setStringLength(void)
		{
			if (sizeof(TyChar) != sizeof(wchar_t))
			{
				_stringLength = -1;
			}
			else
			{
				GDK_ASSERT(_stringLength == (ssize_t)(getBufferLength() / sizeof(wchar_t) - 1));
			}
		}

		__INLINE__ ssize_t getBufferLength(void) const
		{
			return _bufferLength;
		}

		static StringData* getNilString(void)
		{
			static int32_t  g_locked;
			static bool     g_initialized;

			static struct NilString : public StringData
			{
				TyChar	_data[1];
			} g_nilString;


			if (!g_initialized)
			{
				BEGIN_EXCLUSIVE(g_locked)
				{
					if (!g_initialized)
					{
						g_nilString._bufferLength = sizeof(TyChar);
						g_nilString._stringLength = 0;
						g_nilString._refs         = 1;
						g_nilString._data[0]      = 0;

						g_initialized             = true;
					}
				}
				END_EXCLUSIVE()
			}

			return &g_nilString;
		}

		static StringData* allocate(ssize_t bufferLength)
		{
			StringData *pData = (StringData*)GDK_NEW char[sizeof(StringData) + bufferLength];
			if (pData != NULL)
			{
				pData->_bufferLength = bufferLength;
				pData->_stringLength = ((sizeof(TyChar) == sizeof(wchar_t)) ? (bufferLength / sizeof(wchar_t) - 1) : -1);
				pData->_refs         = 1;

				if (sizeof(TyChar) == sizeof(wchar_t))
				{
					GDK_ASSERT(pData->_stringLength >= 0);
				}
			}
			else
			{
				Log::error(__TEXT__("Allocate memory(" SIZE_FMT ") error!"), sizeof(StringData) + bufferLength);
			}
			return pData;
		}
	};


private:
	TyChar	*_pszData;

private:
	__INLINE__ explicit String_T(StringData *pData)
	{
		_pszData = (TyChar*)pData->data();
	}

	__INLINE__ void attach(StringData *newData)
	{
		StringData *oldData = getData();

		_pszData = (TyChar*)newData->data();

		oldData->release();
	}

	__INLINE__ StringData* getData(void) const
	{
		return (StringData*)_pszData - 1;
	}

	void fork(void)
	{
		StringData *oldData = getData();
		ssize_t bufferLength = oldData->getBufferLength();
		StringData *newData = StringData::allocate(bufferLength);
		memCopy(newData->data(), oldData->data(), bufferLength);
		attach(newData);
	}

	ssize_t replace(const TyChar *pszOld, ssize_t oldLength,
					const TyChar *pszNew, ssize_t newLength)
	{
		GDK_ASSERT(pszOld != NULL);
		GDK_ASSERT((ssize_t)(stringBufferLength(pszOld) / sizeof(TyChar) - 1) == oldLength);
		GDK_ASSERT(pszNew != NULL);
		GDK_ASSERT((ssize_t)(stringBufferLength(pszNew) / sizeof(TyChar) - 1) == newLength);


		ssize_t count = 0;
		const TyChar *pszStart = *this;
		while (NULL != (pszStart = stringFindString(pszStart, pszOld)))
		{
			pszStart += oldLength;
			count ++;
		}

		if (count > 0)
		{
			ssize_t len = (newLength - oldLength) * count + getBufferLength() / sizeof(TyChar);

			StringData *pOldData = getData();
			StringData *pNewData =
						(
							newLength != oldLength || pOldData->isShared()
						)
						? StringData::allocate(len * sizeof(TyChar))
						: (pOldData->setStringLength(), pOldData);

			TyChar *pszTarget = pNewData->data();
			const TyChar *pszFind;

			pszStart = *this;

			if (pOldData == pNewData)
			{
				while (NULL != (pszFind = stringFindString(pszStart, pszOld)))
				{
					ssize_t i = (ssize_t)(pszFind - pszStart);

					pszTarget += i;
					memCopy(pszTarget, pszNew, newLength * sizeof(TyChar));
					pszTarget += newLength;

					pszStart += (i + oldLength);
				}
			}
			else
			{
				while (NULL != (pszFind = stringFindString(pszStart, pszOld)))
				{
					ssize_t i = (ssize_t)(pszFind - pszStart);

					memCopy(pszTarget, pszStart, i * sizeof(TyChar));
					pszTarget += i;
					memCopy(pszTarget, pszNew, newLength * sizeof(TyChar));
					pszTarget += newLength;

					pszStart += (i + oldLength);
				}
				memCopy(pszTarget, pszStart,
						sizeof(TyChar) *
							(ssize_t)
							(
								pOldData->data() +
								(pOldData->getBufferLength() / sizeof(TyChar) - 1) -
								pszStart
							)
				);

				pNewData->data()[len - 1] = 0;

				attach(pNewData);
			}
		}

		return count;
	}

	ssize_t insert(ssize_t index, const TyChar *psz, ssize_t strLength)
	{
		GDK_ASSERT(index >= 0 && index < getBufferLength() / (ssize_t)sizeof(TyChar));
		GDK_ASSERT(psz != NULL);
		GDK_ASSERT(stringBufferLength(psz) / sizeof(TyChar) - 1 == strLength);

		ssize_t length = getBufferLength() / sizeof(TyChar) - 1;
		ssize_t newLength = length + strLength;

		const TyChar *pszOld = *this;
		StringData   *pNewData = StringData::allocate(newLength * sizeof(TyChar) + sizeof(TyChar));
		TyChar       *pszNew = (TyChar*)pNewData->data();

		memCopy(pszNew, pszOld, index * sizeof(TyChar));
		memCopy(pszNew + index, psz, strLength * sizeof(TyChar));
		memCopy(pszNew + index + strLength, pszOld + index, (length - index) * sizeof(TyChar));
		pNewData->data()[newLength] = 0;

		attach(pNewData);

		return newLength;
	}

	ssize_t remove(const TyChar *psz, ssize_t length)
	{
		GDK_ASSERT(psz != NULL);
		GDK_ASSERT(stringBufferLength(psz) / sizeof(TyChar) - 1 == length);

		ssize_t count = 0;
		const TyChar *pszSource = *this;
		while (NULL != (pszSource = stringFindString(pszSource, psz)))
		{
			pszSource += length;
			count ++;
		}

		if (count <= 0) return 0;

		ssize_t       size;
		StringData   *pOldData = getData();
		StringData   *pNewData = StringData::allocate(pOldData->getBufferLength() - count * length * sizeof(TyChar));
		TyChar       *pszDest = pNewData->data();
		const TyChar *pszSourceTemp;

		pszSource = *this;
		for (;;)
		{
			pszSourceTemp = pszSource;

			pszSource = stringFindString(pszSource, psz);
			if (pszSource == NULL) break;

			size = (ssize_t)((const char *)pszSource - (const char *)pszSourceTemp);
			memCopy(pszDest, pszSourceTemp, size);
			pszDest = (TyChar*)((char*)pszDest + size);

			pszSource += length;
		}

		size = pOldData->getBufferLength() - (ssize_t)
				(
					(const char *)pszSourceTemp -
					(const char *)pOldData->data()
				);
		if (size > 0)
		{
			memCopy(pszDest, pszSourceTemp, size);
		}

		attach(pNewData);

		return count;
	}

public:
	~String_T(void)
	{
		getData()->release();
	}
	String_T(void)
	{
		_pszData = StringData::getNilString()->addRefs()->data();
	}
	String_T(const String_T &r)
	{
		_pszData = r.getData()->addRefs()->data();
	}
	String_T(const TyChar *psz)
	{
		StringData *newData;
		ssize_t size = (psz != NULL && psz[0] != 0) ? stringBufferLength(psz) : 0;

		if (static_cast<size_t>(size) > sizeof(TyChar))
		{
			newData = StringData::allocate(size);
			memCopy(newData->data(), psz, size);
		}
		else
			newData = StringData::getNilString()->addRefs();

		_pszData = newData->data();
	}
	String_T(int ch)
	{
		StringData *newData;

		if (ch)
		{
			TyChar psz[4];
			ssize_t bufferLength = (charToString(psz, ch) + 1) * sizeof(TyChar);
			newData = StringData::allocate(bufferLength);
			memCopy(newData->data(), psz, bufferLength);
		}
		else
		{
			newData = StringData::getNilString()->addRefs();
		}

		_pszData = newData->data();
	}
	String_T(const TyChar *psz, ssize_t len)
	{
		GDK_ASSERT(len >= 0 && len <= stringLength(psz));

		const TyChar *p = stringSkipChar(psz, len);
		ssize_t strBufferLength = (ssize_t)(p - psz) * sizeof(TyChar);
		StringData *newData;

		while (strBufferLength > 0 && *(p - 1) == 0)
		{
			strBufferLength -= sizeof(TyChar);
		}

		if (strBufferLength <= 0)
		{
			newData = StringData::getNilString()->addRefs();
		}
		else
		{
			newData = StringData::allocate(strBufferLength + sizeof(TyChar));
			memCopy(newData->data(), psz, strBufferLength);
			newData->data()[strBufferLength / sizeof(TyChar)] = 0;
		}

		_pszData = newData->data();
	}

	String_T& setBuffer(const void *data, ssize_t size)
	{
		if (size > 0)
		{
			GDK_ASSERT(data != NULL);

			ssize_t bufsize = (size + (sizeof(TyChar) - 1)) / sizeof(TyChar) * sizeof(TyChar) + sizeof(TyChar);
			StringData* newData = StringData::allocate(bufsize);
			memCopy((char*)newData->data(), data, size);
			memset((char*)newData->data() + size, 0, bufsize - size);
			attach(newData);
		}
		else
		{
			attach(StringData::getNilString()->addRefs());
		}
		return *this;
	}

	__INLINE__ ssize_t getLength(void) const
	{
		return getData()->getStringLength();
	}
	__INLINE__ const TyChar* getBuffer(void) const
	{
		return *this;
	}
	__INLINE__ ssize_t getBufferLength(void) const
	{
		return getData()->getBufferLength();
	}
	__INLINE__ bool empty(void) const
	{
		return getBuffer()[0] == '\0';
	}

	int compare(const TyChar *psz) const
	{
		const TyChar *p = *this;

		if (psz == NULL)
			psz = StringData::getNilString()->data();

		return (p != psz) ? stringCompare(p, psz) : 0;
	}
	int compareNoCase(const TyChar *psz) const
	{
		const TyChar *p = *this;

		if (psz == NULL)
			psz = StringData::getNilString()->data();

		return (psz != p) ? stringCompareNoCase(p, psz) : 0;
	}

	String_T& trimLeft(void)
	{
		const TyChar *begin = _pszData;
		while (*begin)
		{
			const TyChar *p = begin;
			int ch = *begin++;
			if (!isSpace(ch))
			{
				begin = p;
				break;
			}
		}

		if (begin != _pszData)
		{
			const TyChar *end = _pszData + getBufferLength() / sizeof(TyChar) - 1;
			setBuffer(begin, (ssize_t)(end - begin) * sizeof(TyChar));
/*
			operator = (String_T(begin));
*/
		}

		return *this;
	}
	String_T& trimRight(void)
	{
		const TyChar *begin = *this;
		const TyChar *end = begin + getBufferLength() / sizeof(TyChar) - 1;
		const TyChar *pszEnd = end;

		while (begin != end)
		{
			const TyChar *p = end;
			int ch = *(--end);
			if (!isSpace(ch))
			{
				end = p;
				break;
			}
		}

		if (end != pszEnd)
		{
			setBuffer(begin, (ssize_t)(end - begin) * sizeof(TyChar));
/*
			StringData *newData;
			ssize_t strBufferLength = (ssize_t)(end - begin) * sizeof(TyChar);
			if(strBufferLength <= 0)
			{
				newData = StringData::getNilString()->addRefs();
			}
			else
			{
				newData = StringData::allocate(strBufferLength + sizeof(TyChar));
				memCopy(newData->data(), begin, strBufferLength);
				newData->data()[strBufferLength / sizeof(TyChar)] = 0;
			}
			attach(newData);
*/
		}

		return *this;
	}
	String_T& trim(void)
	{
		const TyChar *begin = *this;
		const TyChar *end = begin + getBufferLength() / sizeof(TyChar) - 1;
		const TyChar *pszEnd = end;

		while (*begin)
		{
			const TyChar *p = begin;
			int ch = *begin++;
			if (!isSpace(ch))
			{
				begin = p;
				break;
			}
		}

		while (begin != end)
		{
			const TyChar *p = end;
			int ch = *(--end);
			if (!isSpace(ch))
			{
				end = p;
				break;
			}
		}

		if (begin != _pszData || end != pszEnd)
		{
			setBuffer(begin, (ssize_t)(end - begin) * sizeof(TyChar));
		}

		return *this;
/*
		return trimLeft().trimRight();
*/
	}

	String_T& toUpperCase(void)
	{
		if (getData()->isShared()
		&&  _pszData != StringData::getNilString()->data())
		{
			fork();
		}
		stringUppercase(_pszData);

		return *this;
	}
	String_T& toLowerCase(void)
	{
		if (getData()->isShared()
		&&  _pszData != StringData::getNilString()->data())
		{
			fork();
		}
		stringLowercase(_pszData);

		return *this;
	}

	__INLINE__ const TyChar* c_str() const
	{
		return _pszData;
	}

	__INLINE__ operator const TyChar *() const
	{
		return _pszData;
	}
	__INLINE__ int operator[](ssize_t index) const
	{
		GDK_ASSERT(index >= 0 && index <= getLength());

		int ch;

		stringChar(stringSkipChar(_pszData, index), ch);

		return ch;
	}
#if defined(_M_X64) || defined(__x86_64__) || defined(__IOS__) || defined(_WIN32)// || defined(__ANDROID__)
	__INLINE__ int operator[](int index) const
	{
		return this->operator[](ssize_t(index));
	}
#endif

	String_T& operator=(String_T const& strSrc)
	{
		attach(strSrc.getData()->addRefs());

		return *this;
	}
	String_T& operator=(TyChar const *pszSrc)
	{
		StringData *pData;
		StringData *pOldData = getData();
		ssize_t     bufferLength = (pszSrc != NULL && pszSrc[0] != 0) ? stringBufferLength(pszSrc) : 0;

		if (static_cast<size_t>(bufferLength) > sizeof(TyChar))
		{
			if (bufferLength == getBufferLength()
			&&  !pOldData->isShared())
			{
				pData = pOldData;
				pData->setStringLength();
			}
			else
			{
				pData = StringData::allocate(bufferLength);
			}

			memCopy(pData->data(), pszSrc, bufferLength);
		}
		else
		{
			pData = StringData::getNilString()->addRefs();
		}

		if (pData != pOldData)
		{
			attach(pData);
		}

		return *this;
	}
	String_T  operator+(const String_T &strSrc) const
	{
		ssize_t bufferLength1 = getBufferLength() - sizeof(TyChar);
		if (bufferLength1 <= 0) return String_T(strSrc);

		ssize_t bufferLength2 = strSrc.getBufferLength() - sizeof(TyChar);
		if (bufferLength2 <= 0) return String_T(*this);

		const TyChar *psz1 = *this;
		const TyChar *psz2 = strSrc;

		ssize_t length = bufferLength1 + bufferLength2;

		StringData *pData = StringData::allocate(length + sizeof(TyChar));
		memCopy((char*)pData->data()                , psz1, bufferLength1);
		memCopy((char*)pData->data() + bufferLength1, psz2, bufferLength2 + sizeof(TyChar));

		return String_T(pData);
	}
	String_T  operator+(const TyChar *pszSrc) const
	{
		if (pszSrc == NULL || pszSrc[0] == 0) return String_T(*this);

		ssize_t bufferLength1 = getBufferLength() - sizeof(TyChar);
		if (bufferLength1 <= 0) return String_T(pszSrc);

		ssize_t bufferLength2 = stringBufferLength(pszSrc) - sizeof(TyChar);
		if (bufferLength2 <= 0) return String_T(*this);

		const TyChar *psz1 = *this;
		const TyChar *psz2 = pszSrc;

		ssize_t length = bufferLength1 + bufferLength2;

		StringData *pData = StringData::allocate(length + sizeof(TyChar));
		memCopy((char*)pData->data()                , psz1, bufferLength1);
		memCopy((char*)pData->data() + bufferLength1, psz2, bufferLength2 + sizeof(TyChar));

		return String_T(pData);
	}
	__INLINE__ String_T& operator +=(const String_T &strSrc)
	{
		*this = this->operator +(strSrc);

		return *this;
	}
	__INLINE__ String_T& operator +=(const TyChar *pszSrc)
	{
		*this = this->operator +(pszSrc);

		return *this;
	}
	__INLINE__ String_T& operator +=(int ch)
	{
		TyChar psz[4];

		charToString(psz, ch);

		return this->operator +=(psz);
	}

	__INLINE__ bool operator > (TyChar const *psz) const
	{
		return compare(psz) > 0;
	}
	__INLINE__ bool operator < (TyChar const *psz) const
	{
		return compare(psz) < 0;
	}
	__INLINE__ bool operator ==(TyChar const *psz) const
	{
		return compare(psz) == 0;
	}
	__INLINE__ bool operator !=(TyChar const *psz) const
	{
		return compare(psz) != 0;
	}
	__INLINE__ bool operator >=(TyChar const *psz) const
	{
		return compare(psz) >= 0;
	}
	__INLINE__ bool operator <=(TyChar const *psz) const
	{
		return compare(psz) <= 0;
	}

	__INLINE__ bool operator ==(String_T const &str) const
	{
		return getBufferLength() == str.getBufferLength()
			&& operator == ((TyChar const *)str);
	}
	__INLINE__ bool operator !=(String_T const &str) const
	{
		return !(operator == (str));
	}

	String_T getSubString(ssize_t start, ssize_t count = -1) const
	{
		GDK_ASSERT(start >= 0);

		ssize_t n = getLength();
		if (count < 0 || start > n - count)
		{
			count = n - start;
		}

		if (start == 0 && count == n)
		{
			return *this;
		}

		return String_T(stringSkipChar(_pszData, start), count);
	}
	ssize_t find(int ch, ssize_t start = 0) const
	{
		GDK_ASSERT(start >= 0);

		if (empty()) return -1;

		GDK_ASSERT(start < getLength());

		const TyChar *psz = stringFindChar(stringSkipChar(_pszData, start), ch);

		return (psz == NULL) ? -1 : (ssize_t)(psz - _pszData);
	}
	ssize_t find(const TyChar *pszStr, ssize_t start = 0) const
	{
		GDK_ASSERT(start >= 0);

		if (empty()) return -1;

		GDK_ASSERT(start < getLength());

		const TyChar *psz = stringFindString(stringSkipChar(_pszData, start), pszStr);

		return (psz == NULL) ? -1 : (ssize_t)(psz - _pszData);
	}

	ssize_t vprintf(const TyChar *pszFormat, va_list args)
	{
		va_list tmp_args;
		va_copy(tmp_args, args);
		ssize_t result = 0;
		ssize_t length = getFormatLength(pszFormat, tmp_args);
		if (length > 0)
		{
			StringData *pNewData = StringData::allocate((length + 1) * sizeof(TyChar));
			result = vsprintf(pNewData->data(), pszFormat, args);
			GDK_ASSERT(result == length);
			pNewData->data()[length] = 0;
			attach(pNewData);
		}
		else
		{
		   	attach(StringData::getNilString()->addRefs());
		}
		return result;
	}
	ssize_t format(const TyChar *pszFormat, ...)
	{
		va_list args;
		va_start(args, pszFormat);
		ssize_t result = vprintf(pszFormat, args);
		va_end(args);
		return result;
	}

	ssize_t replace(int chOld, int chNew)
	{
		TyChar pszOld[4], pszNew[4];

		ssize_t n1 = charToString(pszOld, chOld);
		ssize_t n2 = charToString(pszNew, chNew);

		return replace(pszOld, n1, pszNew, n2);
	}
	__INLINE__ ssize_t replace(const TyChar *pszOld, const TyChar *pszNew)
	{
		GDK_ASSERT(pszOld != NULL && pszNew != NULL);

		return replace (pszOld, stringBufferLength(pszOld) / sizeof(TyChar) - 1,
						pszNew, stringBufferLength(pszNew) / sizeof(TyChar) - 1);
	}
	__INLINE__ ssize_t replace(const String_T &strOld, const String_T &strNew)
	{
		return replace (strOld, strOld.getBufferLength() / sizeof(TyChar) - 1,
						strNew, strNew.getBufferLength() / sizeof(TyChar) - 1);
	}
	__INLINE__ ssize_t replace(const String_T &strOld, const TyChar *pszNew)
	{
		GDK_ASSERT(pszNew != NULL);

		return replace (strOld, strOld.getBufferLength() / sizeof(TyChar) - 1,
						pszNew, stringBufferLength(pszNew)/ sizeof(TyChar) - 1);
	}
	__INLINE__ ssize_t replace(const TyChar *pszOld, const String_T &strNew)
	{
		GDK_ASSERT(pszOld != NULL);

		return replace (pszOld, stringBufferLength(pszOld) / sizeof(TyChar) - 1,
						strNew, strNew.getBufferLength() / sizeof(TyChar) - 1);
	}
	ssize_t erase(ssize_t index, ssize_t count = 1)
	{
		GDK_ASSERT(count >= 0 && count < (ssize_t)(getBufferLength() / sizeof(TyChar)));

		if (count > 0)
		{
			ssize_t length = getBufferLength() / sizeof(TyChar);
			ssize_t newBufferLength = (length - count) * sizeof(TyChar);
			ssize_t copyCount = length - (index + count);

			TyChar     *pszOld = _pszData;
			StringData *pNewData = StringData::allocate(newBufferLength);
			TyChar     *pszNew = (TyChar*)pNewData->data();

			memCopy(pszNew      , pszOld                , index * sizeof(TyChar));
			memCopy(pszNew+index, pszOld + index + count, copyCount * sizeof(TyChar));

			attach(pNewData);
		}

		return count;
	}
	__INLINE__ ssize_t insert(ssize_t index, int ch)
	{
		TyChar psz[4];

		return insert(index, psz, charToString(psz, ch));
	}
	__INLINE__ ssize_t insert(ssize_t index, const TyChar *psz)
	{
		return insert(index, psz, stringBufferLength(psz) / sizeof(TyChar) - 1);
	}
	__INLINE__ ssize_t insert(ssize_t index, const String_T &str)
	{
		return insert(index, str, str.getBufferLength() / sizeof(TyChar) - 1);
	}
	__INLINE__ ssize_t remove(int ch)
	{
		TyChar psz[4];

		return remove(psz, charToString(psz, ch));
	}
	__INLINE__ ssize_t remove(const String_T &str)
	{
		return remove(str, str.getBufferLength() / sizeof(TyChar) - 1);
	}
	__INLINE__ ssize_t remove(const TyChar *psz)
	{
		return remove(psz, stringBufferLength(psz) / sizeof(TyChar) - 1);
	}


public:
	template<typename TyIs> friend TyIs& operator >>(TyIs &is, String_T &str) __THROW1;
	template<typename TyOs> friend TyOs& operator <<(TyOs &os, const String_T  &str) __THROW1;

private:
	friend class StringHelper;
};




#if defined(_MSC_VER)
// 使用 gcc 编译如果打开下面代码, 多个cpp文件使用 typeid(String).name() 链接出错,
//	multiple definition of 'typeinfo name for gdk::TString<wchar_t>'
template class GDK_CORE_EXPORT String_T<char>;
template class GDK_CORE_EXPORT String_T<utf8_t>;
template class GDK_CORE_EXPORT String_T<wchar_t>;
#endif


typedef String_T<ansi_t>	StringAnsi;
typedef String_T<utf8_t>	StringUtf8;
typedef String_T<wchar_t>	StringWide;


#if defined(_UNICODE)
	typedef StringWide	String;
#else
	typedef StringUtf8	String;
#endif


template<typename TyChar>
String_T<TyChar> operator+ (const TyChar* l, const String_T<TyChar>& r)
{
	return String_T<TyChar>(l) + r;
}

template GDK_CORE_EXPORT StringAnsi operator+ (const StringAnsi::TyChar* l, const StringAnsi& r);
template GDK_CORE_EXPORT StringUtf8 operator+ (const StringUtf8::TyChar* l, const StringUtf8& r);
template GDK_CORE_EXPORT StringWide operator+ (const StringWide::TyChar* l, const StringWide& r);

//template __PRINTF_FORMAT__(2, 3)  ssize_t StringAnsi::format(const StringAnsi::TyChar *pszFormat, ...);
template __PRINTF_FORMAT__(2, 3)  ssize_t StringUtf8::format(const StringUtf8::TyChar *pszFormat, ...);
template __WPRINTF_FORMAT__(2, 3) ssize_t StringWide::format(const StringWide::TyChar *pszFormat, ...);



class StringHelper
{
public:
	GDK_CORE_EXPORT static StringWide ansiToWide(const ansi_t *pszStr);
	GDK_CORE_EXPORT static StringAnsi wideToAnsi(const wchar_t *pszStr);

	GDK_CORE_EXPORT static StringWide utf8ToWide(const utf8_t *pszStr);
	GDK_CORE_EXPORT static StringUtf8 wideToUtf8(const wchar_t *pszStr);

	GDK_CORE_EXPORT static StringUtf8 ansiToUtf8(const ansi_t *pszStr);
	GDK_CORE_EXPORT static StringAnsi utf8ToAnsi(const utf8_t *pszStr);
};



class StringConvert
{
private:
	const ansi_t*	_ansi;
	const utf8_t*	_utf8;
	const wchar_t*	_wide;

public:
	__INLINE__ StringConvert(const ansi_t *ansi) : _ansi(ansi), _utf8(NULL), _wide(NULL) {}
	__INLINE__ StringConvert(const utf8_t *utf8) : _ansi(NULL), _utf8(utf8), _wide(NULL) {}
	__INLINE__ StringConvert(const wchar_t *wide): _ansi(NULL), _utf8(NULL), _wide(wide) {}

	GDK_CORE_EXPORT operator StringAnsi () const;
	GDK_CORE_EXPORT operator StringUtf8 () const;
	GDK_CORE_EXPORT operator StringWide () const;

	GDK_CORE_EXPORT StringAnsi toStringAnsi(void) const;
	GDK_CORE_EXPORT StringUtf8 toStringUtf8(void) const;
	GDK_CORE_EXPORT StringWide toStringWide(void) const;
	GDK_CORE_EXPORT String     toString    (void) const;
};



GDK_CORE_EXPORT String convertToString(const StringAnsi &in);
GDK_CORE_EXPORT String convertToString(const StringUtf8 &in);
GDK_CORE_EXPORT String convertToString(const StringWide &in);



/*
template<typename TyIs,typename TyChar>
TyIs& operator >>(TyIs &is, String_T<TyChar> &str) __THROW1
{
	typedef typename String_T<TyChar>::StringData StringData;

	StringData *pNewData=NULL;
	ssize_t    len;

	is>>len;
	if( len<0 )
	{
		goto err;
	}
	if( sizeof(TyChar)==sizeof(char) )
	{
		if( len>is.available() )
		{
			goto err;
		}
	}
	else
	{
		if( len*2>is.available() )
		{
			goto err;
		}
	}

	pNewData=StringData::allocate((len+1)*sizeof(TyChar));
	if(pNewData==NULL) goto err;

	if( sizeof(TyChar)==sizeof(char) )
	{
		if( len!=is.read(pNewData->data(),len) )
		{
			goto err;
		}
	}
	else
	{
		__TRY
		{
			TyChar *p=pNewData->data();
			for(ssize_t i=0;i<len;++i)
			{
				is>>p[i];
			}
		}
		__CATCH(e)
		{
			(void)&e;
			goto err;
		}
	}

	pNewData->data()[len]=0;
	str.attach(pNewData);

	return is;

err:
	if(pNewData!=NULL)
	{
		pNewData->release();
	}

	__THROW__(__TEXT__("TyIs& operator >>(TyIs&,String_T<TyChar>&)"));
}
template<typename TyOs,typename TyChar>
TyOs& operator <<(TyOs &os,String_T<TyChar> const &str) __THROW1
{
	ssize_t len=(str.getBufferLength()-sizeof(TyChar))/sizeof(TyChar);
	os<<len;

	if( sizeof(TyChar)==sizeof(char) )
	{
		if( len!=os.write((TyChar const*)str,len) )
		{
			__THROW__(__TEXT__("TyOs& operator <<(TyOs&,String_T<TyChar>&)"));
		}
	}
	else
	{
		const TyChar *p=(TyChar const*)str;
		for(ssize_t i=0;i<len;++i)
		{
			os<<p[i];
		}
	}

	return os;
}
*/
template<typename TyIs>
TyIs& operator >>(TyIs &is, StringUtf8 &str) __THROW1
{
	typedef typename StringUtf8::StringData StringData;

	StringData *newData = NULL;
	Varint len;

	is >> len;
	if (len < 0 || len > is.available())
		goto err;

	newData = StringData::allocate((len + 1) * ssize_t(sizeof(StringUtf8::TyChar)));
	if (newData == NULL
	||	len != is.read(newData->data(), len)
	) goto err;

	newData->data()[len] = 0;
	str.attach(newData);

	return is;

err:
	if (newData != NULL)
	{
		newData->release();
	}

	__THROW__(__TEXT__("TyIs& operator >>(TyIs&, String&)"));
}
template<typename TyOs>
TyOs& operator <<(TyOs &os, const StringUtf8 &str) __THROW1
{
	Varint len = static_cast<ssize_t>((str.getBufferLength() - sizeof(StringUtf8::TyChar)) / sizeof(StringUtf8::TyChar));
	os << len;

	if (len != os.write((const StringUtf8::TyChar *)str, len))
	{
		__THROW__(__TEXT__("TyOs& operator <<(TyOs&, const String&)"));
	}
	return os;
}

template<typename TyIs>
TyIs& operator >>(TyIs &is, StringAnsi &str) __THROW1
{
	StringUtf8 utf8;
	is >> utf8;
	str = StringHelper::utf8ToAnsi(utf8);
	return is;
}
template<typename TyOs>
TyOs& operator <<(TyOs &os, const StringAnsi &str) __THROW1
{
	return os << StringHelper::ansiToUtf8(str);
}

template<typename TyIs>
TyIs& operator >>(TyIs &is, StringWide &str) __THROW1
{
	StringUtf8 utf8;
	is >> utf8;
	str = StringHelper::utf8ToWide(utf8);
	return is;
}
template<typename TyOs>
TyOs& operator <<(TyOs &os, const StringWide &str) __THROW1
{
	return os << StringHelper::wideToUtf8(str);
}



#if defined(_WIN32)
#	pragma warning(pop)
#endif


}//namespace gdk


#endif //__GDK_STRING_H__
